package com.novax.ex.activity.provider.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.novax.ex.activity.infrastructure.entity.*;
import com.novax.ex.activity.infrastructure.mapper.*;
import com.novax.ex.activity.provider.api.*;
import com.novax.ex.activity.provider.api.model.*;
import com.novax.ex.activity.provider.aspect.RetryOnFailure;
import com.novax.ex.activity.provider.common.TaskCenter;
import com.novax.ex.common.base.BaseMapper;
import com.novax.ex.common.base.BaseService;
import com.novax.ex.common.constant.ActivityConstants;
import com.novax.ex.common.constant.InternationalCode;
import com.novax.ex.common.core.redis.RedisUtil;
import com.novax.ex.common.exception.BusinessException;
import com.novax.ex.common.results.ReturnResult;
import com.novax.ex.common.util.Snowflake;
import com.novax.ex.common.util.SpringBeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.UriUtils;

import jakarta.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TaskVersionInfoService extends BaseService {

    // 使用rapid_api代替twitter_api
//    @Value("${twitter.verify.rapid.api:https://twitter-api45.p.rapidapi.com/checkfollow.php?user=%S&follows=SuperExet}")
    @Value("${twitter.verify.rapid.api}")
    private String RAPID_API;

    // api_key
//    @Value("${twitter.verify.rapid.key:5f6ef127demsh58142bab8c73c2cp1c8774jsn0f3105f6c548}")
    @Value("${twitter.verify.rapid.key}")
    private String apiKey;

    // api_host
//    @Value("${twitter.verify.rapid.host:twitter-api45.p.rapidapi.com}")
    @Value("${twitter.verify.rapid.host}")
    private String apiHost;

    @Resource
    private UserApi userApi;

    @Resource
    private TaskVersionInfoMapper taskVersionInfoMapper;
    @Resource
    private TaskVersionConfigMapper taskVersionConfigMapper;
    @Resource
    private TaskUserProgressMapper taskUserProgressMapper;
    @Resource
    private TaskRewardMapper taskRewardMapper;
    @Resource
    private TaskAwardLogMapper taskAwardLogMapper;
    @Resource
    private TaskEtRewardsMapper taskEtRewardsMapper;
    @Resource
    private TaskDataMapper taskDataMapper;
    @Resource
    private WalletApi walletApi;
    @Resource
    private OtcApi otcApi;
    @Resource
    private SwapApi swapApi;
    @Resource
    private SpotApi spotApi;
    @Resource
    private ResourceApi resourceApi;
    @Resource
    private SignInnerApi signInnerApi;
    @Resource
    private InternationalApi internationalApi;


    @Override
    protected BaseMapper getBaseMapper() {
        return taskVersionInfoMapper;
    }

    public List<UserTaskProgressDO> findUserTasks(Long uid, String language) {

        // 源数据
        Long versionId = findUserVersionId(uid);
        List<UserTaskProgressDO> userTaskProgressDOS = taskVersionInfoMapper.selectUserTaskList(language, versionId);

        if (userTaskProgressDOS.stream().allMatch(x -> Objects.isNull(x.getTitle()))) {
            userTaskProgressDOS = taskVersionInfoMapper.selectUserTaskList("en", versionId);
        }
        userTaskProgressDOS = userTaskProgressDOS.stream().skip(TaskCenter.STEP_TWO).collect(Collectors.toList());

        // 用户完成任务的进度
        TaskUserProgress taskUserProgress;
        String repeatKey = ActivityConstants.redisType.NEW_USER + uid;
        Object redisUserTaskProgress = RedisUtil.get(repeatKey);
        if (redisUserTaskProgress != null) {
            String taskProgress = (String) redisUserTaskProgress;
            taskUserProgress = JSON.parseObject(taskProgress, TaskUserProgress.class);
        } else {
            taskUserProgress = taskUserProgressMapper.selectByUid(uid);
            RedisUtil.set(ActivityConstants.redisType.NEW_USER + uid, JSON.toJSONString(taskUserProgress), 10L, TimeUnit.MINUTES);
        }

        // 如果为空说明是老用户一次也没有签到，或者是新用户刚好做完前三步都任务，都是设置为一个签到任务也没有完成
        if (Objects.isNull(taskUserProgress) || Objects.equals(taskUserProgress.getStep(), TaskCenter.STEP_THREE)) {
            userTaskProgressDOS.forEach(item -> {
                item.setIsCompleted(TaskCenter.UN_FINISH);
                if (Objects.equals(item.getStep(), TaskCenter.STEP_FOUR)) {
                    item.setIsTodayTask(TaskCenter.YES);
                }
            });
        } else {
            if (taskUserProgress.getStep() < TaskCenter.STEP_THREE) {
                userTaskProgressDOS.forEach(item -> {
                    item.setIsCompleted(TaskCenter.UN_FINISH);
                    item.setIsTodayTask(TaskCenter.NO);
                });
            } else {
                TaskUserProgress finalTaskUserProgress = taskUserProgress;
                userTaskProgressDOS.forEach(item -> {
                    if (item.getStep() <= finalTaskUserProgress.getStep()) {
                        item.setIsCompleted(TaskCenter.FINISH);
                    }
                });
                if (isSameDay(taskUserProgress.getLeastFinishTime(), new Date())) {
                    userTaskProgressDOS.get(taskUserProgress.getStep() - 4).setIsTodayTask(TaskCenter.YES);
                } else {
                    if (Objects.equals(taskUserProgress.getStep(), TaskCenter.MAX_STEP)) {
                        userTaskProgressDOS.get(6).setIsTodayTask(TaskCenter.NO);
                    } else {
                        userTaskProgressDOS.get(taskUserProgress.getStep() - 3).setIsTodayTask(TaskCenter.YES);
                    }
                }
            }
        }
        return userTaskProgressDOS;
    }

    // 确定用户处在那一步
    @Transactional(rollbackFor = Exception.class)
    public String receive(Long uid, String account) {
        TaskUserProgress taskUserProgress = taskUserProgressMapper.selectByUid(uid);
        int step;
        if (Objects.isNull(taskUserProgress)) {
            step = TaskCenter.STEP_FOUR;
        } else {
            step = taskUserProgress.getStep() + TaskCenter.STEP_ONE;
        }
        // 控制用户不能完成7天签到之后的任务
        if (step > TaskCenter.MAX_STEP) {
            log.info("用户ID:[{}]，以达最大领奖步骤，七天签到奖励已经完成，不能再继续领取奖励了", uid);
            return InternationalCode.ALL_COMPLETE_TASK;
        }
        TaskVersionInfoService service = SpringBeanUtils.getBean(TaskVersionInfoService.class);
        return service.userSignProgress(uid, step, account);
    }

    @Transactional(rollbackFor = Exception.class)
    public String receiveV2(Long uid, String account) {
        TaskUserProgress taskUserProgress = taskUserProgressMapper.selectByUid(uid);
        int step;
        if (Objects.isNull(taskUserProgress)) {
            step = TaskCenter.STEP_FOUR;
        } else {
            step = taskUserProgress.getStep() + TaskCenter.STEP_ONE;
        }
        // 控制用户不能完成7天签到之后的任务
        if (step > TaskCenter.MAX_STEP) {
            log.info("用户ID:[{}]，以达最大领奖步骤，七天签到奖励已经完成，不能再继续领取奖励了", uid);
            return InternationalCode.ALL_COMPLETE_TASK;
        }
        TaskVersionInfoService service = SpringBeanUtils.getBean(TaskVersionInfoService.class);
        return service.userSignProgressV2(uid, step, account);
    }

    /**
     * 用户完成任意交易
     *
     * @param uid              用户ID
     * @param transactionCount 后管查出来的，完成任务需要的交易量
     * @param type             0：所有的交易量，1：当天的交易量
     * @return 是否完成任务
     */
    public Boolean finishTrading(Long uid, Integer transactionCount, Integer type) {
        transactionCount = Objects.isNull(transactionCount) ? 0 : transactionCount;
        Integer swapData = swapApi.swapCount(uid, type).getData();
        int swapCount = Objects.isNull(swapData) ? 0 : swapData;
        Integer spotData = spotApi.spotCount(uid, type).getData();
        int spotCount = Objects.isNull(spotData) ? 0 : spotData;
        return spotCount + swapCount >= transactionCount;
    }

    /**
     * 用户完成合约交易
     *
     * @param uid              用户ID
     * @param transactionCount 后管查出来的，完成任务需要的交易量
     * @return 是否完成任务
     */
    public Boolean finishSwap(Long uid, Integer transactionCount) {
        int total = Objects.isNull(transactionCount) ? 0 : transactionCount;
        // 当天合约的交易量
        Integer swapCount = swapApi.swapCount(uid, 1).getData();
        return swapCount >= total;
    }

    /**
     * 现货交易
     */
    public Boolean finishSpot(Long uid, Integer transactionCount) {
        int total = Objects.isNull(transactionCount) ? 0 : transactionCount;
        Integer spotCount = spotApi.spotCount(uid, 1).getData();
        return spotCount >= total;
    }


    /**
     * 查询用户入金的任务是不是完成了
     */
    public Boolean finishDeposit(Long uid, Integer type, Integer rechargeCount) {

        int totalCount = Objects.isNull(rechargeCount) ? 0 : rechargeCount;
        Integer walletData = walletApi.finishDeposit(uid, type).getData();
        int walletCount = Objects.isNull(walletData) ? 0 : walletData;
        Long otcData = otcApi.count(uid, type).getData();
        int otcCount = Objects.isNull(otcData) ? 0 : otcData.intValue();
        return walletCount + otcCount >= totalCount;
    }


    public Boolean finishDepositV1(Long uid, Integer type, Integer rechargeCount) {

        String repeatKey = ActivityConstants.redisType.FINISH_DEPOSIT + uid + type;
        Object finishDepositV1 = RedisUtil.get(repeatKey);

        if (null != finishDepositV1) {
            return (Boolean) finishDepositV1;
        } else {
            int totalCount = Objects.isNull(rechargeCount) ? 0 : rechargeCount;
            Integer walletData = walletApi.finishDeposit(uid, type).getData();
            int walletCount = Objects.isNull(walletData) ? 0 : walletData;
            Long otcData = otcApi.count(uid, type).getData();
            int otcCount = Objects.isNull(otcData) ? 0 : otcData.intValue();
            boolean b = walletCount + otcCount >= totalCount;
            RedisUtil.set(repeatKey, b, 2L, TimeUnit.HOURS);
            return b;
        }
    }

    /**
     * 查询用户的版本信息，如果是新用户，那么他在注册的时候一定会在task_user_progress中记录(MQ消息消费的时候，会插入数据)
     * 如果是老用户他如果签到了，就会在task_user_progress记录，如果在task_user_progress中没有查出来 那么就是老用户 直接最老的版本给到他
     *
     * @return 版本ID
     */
    public Long findUserVersionId(Long userId) {
        TaskUserProgress param = new TaskUserProgress();
        param.setUid(userId);
        TaskUserProgress taskUserProgress = taskUserProgressMapper.selectByCondition(param);
        if (Objects.nonNull(taskUserProgress)) {
            return taskUserProgress.getVersionId();
        }
        TaskVersionConfig taskVersionConfig = taskVersionConfigMapper.selectFirstVersion();
        return taskVersionConfig.getId();
    }

    /**
     * 用户注册奖励方法的逻辑单独拿出来
     *
     * @param userId 用户ID
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean userRegisterReward(Long userId) {
        Date registerTime;
        try {
            registerTime = userApi.info(userId).getData().getCreateTime();
        } catch (Exception e) {
            log.warn("Feign远程调用UESER服务,查询用户的注册时间时报错。uid=[{}]", userId);
            throw new RuntimeException(e);
        }
        if (Objects.isNull(registerTime)) {
            registerTime = new Date();
        }
        TaskVersionConfig taskVersionConfig = taskVersionConfigMapper.selectRecentVersion(registerTime);
        if (Objects.isNull(taskVersionConfig)) {
            taskVersionConfig = taskVersionConfigMapper.selectFirstVersion();
        }
        return userReward(userId, TaskCenter.STEP_ONE, taskVersionConfig.getId());
    }

    /**
     * 用户领取奖励的逻辑
     *
     * @param uid  用户ID
     * @param step 用户想要领取第几步的奖励
     * @return
     */
    public String userSignProgress(Long uid, Integer step, String account) {
        TaskUserProgress taskUserProgress = taskUserProgressMapper.selectByUid(uid);
        if (step >= TaskCenter.STEP_FIVE) {
            if (!isAfterDay(taskUserProgress.getLeastFinishTime())) {
                log.info("上一次领取奖励的UTC-0时间是[{}], 现在的UTC-0的时间是[{}], 当前时间未在上次领奖时间的第二天甚至以后，不能领取奖励",
                        LocalDateTimeUtil.of(DateUtil.convertTimeZone(taskUserProgress.getLeastFinishTime(), ZoneId.of("UTC"))),
                        LocalDateTimeUtil.of(DateUtil.convertTimeZone(new Date(), ZoneId.of("UTC"))));
                return InternationalCode.COMPLETE_TASK;
            }
        }
        // 用户版本
        Long userVersionId = findUserVersionId(uid);
        // 用户在这一步的任务是啥
        TaskVersionInfo taskVersionInfo = taskVersionInfoMapper.selectByStepAndVersionId(step, userVersionId);
        int tempId = taskVersionInfo.getTaskTemplateId().intValue();
        if (tempId == TaskCenter.STEP_ONE || tempId == TaskCenter.STEP_TWO) {
            if (StringUtils.isBlank(account)) {
                return InternationalCode.LACK_VALUE;
            }
        }
        // 用户是否完成
        Boolean isFinish = isFindVersionTask(uid, taskVersionInfo, account);
        if (isFinish) {
            this.userReward(uid, step, userVersionId);
            return InternationalCode.OPERATION_SUCCESS;
        } else {
            log.info("用户:[{}] 未完成步骤：[{}]所对应的任务，不能领取奖励", uid, step);
            return InternationalCode.UN_FINISH_TASK;
        }
    }


    public String userSignProgressV2(Long uid, Integer step, String account) {
        TaskUserProgress taskUserProgress = taskUserProgressMapper.selectByUid(uid);
        if (step >= TaskCenter.STEP_FIVE) {
            if (!isAfterDay(taskUserProgress.getLeastFinishTime())) {
                log.info("上一次领取奖励的UTC-0时间是[{}], 现在的UTC-0的时间是[{}], 当前时间未在上次领奖时间的第二天甚至以后，不能领取奖励",
                        LocalDateTimeUtil.of(DateUtil.convertTimeZone(taskUserProgress.getLeastFinishTime(), ZoneId.of("UTC"))),
                        LocalDateTimeUtil.of(DateUtil.convertTimeZone(new Date(), ZoneId.of("UTC"))));
                return InternationalCode.COMPLETE_TASK;
            }
        }
        // 用户版本
        Long userVersionId = findUserVersionId(uid);
        // 用户在这一步的任务是啥
        TaskVersionInfo taskVersionInfo = taskVersionInfoMapper.selectByStepAndVersionId(step, userVersionId);
//        int tempId = taskVersionInfo.getTaskTemplateId().intValue();
//        if (tempId == TaskCenter.STEP_ONE || tempId == TaskCenter.STEP_TWO) {
//            if (StringUtils.isBlank(account)) {
//                return InternationalCode.LACK_VALUE;
//            }
//        }

        // 用户是否完成
        Pair<Boolean, String> findVersionTask = isFindVersionTaskV2(uid, taskVersionInfo, account);
        if (findVersionTask.getKey()) {
            this.userReward(uid, step, userVersionId);
            return InternationalCode.OPERATION_SUCCESS;
        } else {
            log.info("用户:[{}] 未完成步骤：[{}]所对应的任务，不能领取奖励", uid, step);
            return findVersionTask.getValue();
        }
    }

    /**
     * 查询用户想要领取奖励对应的任务是否完成
     *
     * @return 是否真的完成了任务
     */
    public Boolean isFindVersionTask(Long uid, TaskVersionInfo taskVersionInfo, String account) {
        switch (taskVersionInfo.getTaskTemplateId().intValue()) {
            case 1:
                if (StringUtils.isBlank(account)) {
                    log.info("用户：[{}],输入的Twitter账号为空,因为不能完成任务", uid);
                    return Boolean.FALSE;
                }
                TaskData taskData = new TaskData();
                taskData.setUserId(uid);
                taskData.setTwitterTime(new Date());
                taskData.setTwitter(account);
                taskData.setCreator(uid);
                taskData.setUpdater(uid);
                return insertOrUpdateTaskData(taskData);
            case 2:
                if (StringUtils.isBlank(account)) {
                    log.info("用户：[{}],输入的Telegram账号为空,因为不能完成任务", uid);
                    return Boolean.FALSE;
                }
                TaskData task = new TaskData();
                task.setUserId(uid);
                task.setTelegramTime(new Date());
                task.setTelegram(account);
                task.setCreator(uid);
                task.setUpdater(uid);
                return insertOrUpdateTaskData(task);
            case 3:
                if (Objects.equals(taskVersionInfo.getStep(), TaskCenter.STEP_TWO)) {
                    return finishDeposit(uid, 0, taskVersionInfo.getRechargeCount());
                }
                return finishDeposit(uid, 1, taskVersionInfo.getRechargeCount());
            case 4:
                return finishSwap(uid, taskVersionInfo.getTransactionCount());
            case 5:
                return finishSpot(uid, taskVersionInfo.getTransactionCount());
            case 6:
                if (Objects.equals(taskVersionInfo.getStep(), TaskCenter.STEP_THREE)) {
                    return finishTrading(uid, taskVersionInfo.getTransactionCount(), TaskCenter.NOT_TRAD_TODAY);
                }
                return finishTrading(uid, taskVersionInfo.getTransactionCount(), TaskCenter.TRAD_TODAY);
            default:
                return null;
        }
    }


    /**
     * V2版本引入了错误类型的机制
     *
     * @param uid             用户ID
     * @param taskVersionInfo 用户任务详情
     * @param account         账户
     * @return 是否完成， 状态码是多少
     */
    public Pair<Boolean, String> isFindVersionTaskV2(Long uid, TaskVersionInfo taskVersionInfo, String account) {
        switch (taskVersionInfo.getTaskTemplateId().intValue()) {
            case 1:

                if (Objects.isNull(account)) {
                    return Pair.of(Boolean.FALSE, InternationalCode.OPERATION_ERROR);
                }

                if (Objects.equals("", account.trim()) || account.length() > 50) {
                    return Pair.of(Boolean.FALSE, InternationalCode.CHECK_FAILED);
                }

                Object verify = RedisUtil.get(ActivityConstants.redisType.TWITTER_VERIFY);
                if (Objects.isNull(verify)) {
                    TaskData taskData = new TaskData();
                    taskData.setUserId(uid);
                    taskData.setTwitter(account);
                    taskData.setTwitterTime(new Date());
                    insertOrUpdateTaskData(taskData);
                    return Pair.of(Boolean.TRUE, InternationalCode.OPERATION_SUCCESS);
                }

                String code = verifyFollow(uid, account);
                return Pair.of(Objects.equals(code, InternationalCode.OPERATION_SUCCESS), code);

            case 2:
                if (StringUtils.isBlank(account)) {
                    log.info("用户：[{}],输入的Telegram账号为空,因为不能完成任务", uid);
                    return Pair.of(Boolean.FALSE, InternationalCode.LACK_VALUE);
                }
                TaskData task = new TaskData();
                task.setUserId(uid);
                task.setTelegramTime(new Date());
                task.setTelegram(account);
                task.setCreator(uid);
                task.setUpdater(uid);
                Boolean aBoolean = insertOrUpdateTaskData(task);
                return Pair.of(aBoolean, InternationalCode.OPERATION_SUCCESS);
            case 3:
                if (Objects.equals(taskVersionInfo.getStep(), TaskCenter.STEP_TWO)) {
                    return Pair.of(finishDeposit(uid, 0, taskVersionInfo.getRechargeCount()), InternationalCode.UN_FINISH_TASK);
                }
                return Pair.of(finishDeposit(uid, 1, taskVersionInfo.getRechargeCount()), InternationalCode.UN_FINISH_TASK);
            case 4:
                return Pair.of(finishSwap(uid, taskVersionInfo.getTransactionCount()), InternationalCode.UN_FINISH_TASK);
            case 5:
                return Pair.of(finishSpot(uid, taskVersionInfo.getTransactionCount()), InternationalCode.UN_FINISH_TASK);
            case 6:
                if (Objects.equals(taskVersionInfo.getStep(), TaskCenter.STEP_THREE)) {
                    return Pair.of(finishTrading(uid, taskVersionInfo.getTransactionCount(), TaskCenter.NOT_TRAD_TODAY), InternationalCode.UN_FINISH_TASK);
                }
                return Pair.of(finishTrading(uid, taskVersionInfo.getTransactionCount(), TaskCenter.TRAD_TODAY), InternationalCode.UN_FINISH_TASK);
            default:
                return null;
        }
    }

    /**
     * 用户签到领取奖励 在领取奖励成功以后，将用户完成的步骤记录在表里边
     */
    public Boolean userReward(Long userId, Integer step, Long versionId) {
        TaskReward taskReward;
        TaskUserProgress taskProgress = taskUserProgressMapper.selectByUid(userId);
        if (step <= 3) {
            taskReward = taskRewardMapper.selectByStep(step);
        } else {
            if (Objects.nonNull(taskProgress) && isConsecutiveDays(taskProgress.getLeastFinishTime())) {
                taskReward = taskRewardMapper.selectByStep(taskProgress.getFinishCount() + 4);
            } else {
                taskReward = taskRewardMapper.selectByStep(4);
            }
        }

        // 三种类型的奖励
        switch (taskReward.getType()) {
            case 1:
            case 4:
                // ET/SCS 插入ET奖励的表
                TaskEtRewards taskEtRewards = new TaskEtRewards();
                taskEtRewards.setVersion(versionId);
                taskEtRewards.setUserId(userId);
                taskEtRewards.setCreator(userId);
                taskEtRewards.setUpdater(userId);
                taskEtRewards.setTotalFreeze(taskReward.getAmount());
                taskEtRewards.setCurrency(taskReward.getCurrency());
                Boolean flag = etAward(taskEtRewards);
                // 插入用户奖励的表
                int affectCount = taskRewardLog(userId, step, versionId, taskReward);
                // 插入用户完成步骤的表
                TaskUserProgress taskUserProgress = new TaskUserProgress();
                taskUserProgress.setUid(userId);
                taskUserProgress.setVersionId(versionId);
                taskUserProgress.setStep(step);
                taskUserProgress.setLeastFinishTime(new Date());
                Boolean isOk = userStepProgress(taskUserProgress);
                return flag && affectCount > 0 && isOk;
            case 2:
                // 可用币种奖励
                // 插入用户奖励表中
                int affect = taskRewardLog(userId, step, versionId, taskReward);
                // 插入用户完成步骤的表
                TaskUserProgress progress = new TaskUserProgress();
                progress.setUid(userId);
                progress.setVersionId(versionId);
                progress.setStep(step);
                Boolean isTure = userStepProgress(progress);
                // 插入现货可用资产和资产记录表里边
                AssetChangeRequest assetChangeRequest = new AssetChangeRequest();
                assetChangeRequest.setAmount(taskReward.getAmount());
                assetChangeRequest.setUserId(userId);
                assetChangeRequest.setSymbol(taskReward.getCurrency() + "_usdt");
                assetChangeRequest.setOrderId(Snowflake.generateId());
                assetChangeRequest.setCurrency(taskReward.getCurrency());
                assetChangeRequest.setOperation(TaskCenter.TASK_AWARD);
                try {
                    spotApi.assetChange(assetChangeRequest);
                } catch (Exception e) {
                    log.warn("任务中心领取奖励接口-用户ID:[{}],在领取可用币种奖励的时候，远程调用spot服务报错。需要插入到现货资产和财务记录的数据：[{}]",
                            userId, JSON.toJSONString(assetChangeRequest), e);
                }
                return affect > 0 && isTure;
            case 3:
                // 插入用户奖励表中
                int insertLog = taskRewardLog(userId, step, versionId, taskReward);
                // 插入用户完成步骤
                TaskUserProgress userProgress = new TaskUserProgress();
                userProgress.setUid(userId);
                userProgress.setVersionId(versionId);
                userProgress.setStep(step);
                Boolean findStepAdd = userStepProgress(userProgress);
                // 插入resource中的盲盒奖励表中
                DrawUserDetailRequest request = new DrawUserDetailRequest();
                request.setAmount(taskReward.getAmount().intValue());
                try {
                    resourceApi.drawByTaskCenter(userId, request);
                } catch (Exception e) {
                    log.warn("任务中心领取奖励接口-用户ID:[{}],在领取盲盒奖励的时候，远程调用resource服务报错。需要插入或添加到[draw_user_detail]表中的数据：[{}]",
                            userId, JSON.toJSONString(request), e);
                }
                return insertLog > 0 && findStepAdd;
            case 5:
                // 插入用户奖励表中
                int flag5 = taskRewardLog(userId, step, versionId, taskReward);
                // 插入用户完成步骤
                TaskUserProgress userProgress5 = new TaskUserProgress();
                userProgress5.setUid(userId);
                userProgress5.setVersionId(versionId);
                userProgress5.setStep(step);
                Boolean findStepAdd5 = userStepProgress(userProgress5);
                // 合约手续费抵扣券
                CouponRequest req = new CouponRequest();
                try {
                    req.setUserId(userId);
                    req.setSourceType(3);
                    req.setCurrency(taskReward.getCurrency());
                    req.setAmount(taskReward.getAmount());
                    req.setExpireDays(taskReward.getDays());
                    req.setExpireTime(LocalDateTime.now().plusDays(taskReward.getDays()));
                    signInnerApi.issueCoupon(req);
                } catch (Exception e) {
                    log.warn("任务中心领取奖励接口-用户ID:[{}],在领取合约手续费抵扣券，远程调用resource服务报错。[{}]",
                            userId, JSON.toJSONString(req), e);
                }
                return flag5 > 0 && findStepAdd5;
            case 6:
                // 插入用户奖励表中
                int flag6 = taskRewardLog(userId, step, versionId, taskReward);
                // 插入用户完成步骤
                TaskUserProgress userProgress6 = new TaskUserProgress();
                userProgress6.setUid(userId);
                userProgress6.setVersionId(versionId);
                userProgress6.setStep(step);
                Boolean findStepAdd6 = userStepProgress(userProgress6);
                // VIP升级券
                UpVipRequest upVipRequest = new UpVipRequest();
                try {
                    upVipRequest.setUserId(userId);
                    upVipRequest.setSourceType(3);
                    upVipRequest.setExpireDays(taskReward.getDays());
                    upVipRequest.setExpireTime(LocalDateTime.now().plusDays(taskReward.getDays()));
                    signInnerApi.upVip(upVipRequest);
                } catch (Exception e) {
                    log.warn("任务中心领取奖励接口-用户ID:[{}],在领取 VIP升级券，远程调用resource服务报错。[{}]",
                            userId, JSON.toJSONString(upVipRequest), e);
                }

                return flag6 > 0 && findStepAdd6;
            default:
                return Boolean.FALSE;
        }
    }

    private int taskRewardLog(Long userId, Integer step, Long versionId, TaskReward taskReward) {
        TaskAwardLog taskAwardLog = new TaskAwardLog();
        setAttribute(step, taskAwardLog);
        taskAwardLog.setVersionId(versionId);
        taskAwardLog.setUserId(userId);
        taskAwardLog.setStep(step);
        taskAwardLog.setAmount(taskReward.getAmount());
        taskAwardLog.setCreator(userId);
        taskAwardLog.setUserId(userId);
        taskAwardLog.setAwardType(taskReward.getType());
        taskAwardLog.setCurrency(taskReward.getCurrency());
        return taskAwardLogMapper.insertSelective(taskAwardLog);
    }

    public Boolean etAward(TaskEtRewards taskEtRewards) {
        int affectCount;
        if (taskEtRewardsMapper.countByUserId(taskEtRewards.getUserId(), taskEtRewards.getCurrency()) > 0) {
            affectCount = taskEtRewardsMapper.updateTotalFreezeAndUserId(taskEtRewards.getTotalFreeze(),
                    taskEtRewards.getUserId(), taskEtRewards.getCurrency());
        } else {
            affectCount = taskEtRewardsMapper.insertSelective(taskEtRewards);
        }
        return affectCount > 0;
    }


    /**
     * 用户每完成一步，就在这个表里边记录一次 这里一个用户只有一条记录
     *
     * @param progress 用户完成任务的信息
     * @return 是否成功
     */
    public Boolean userStepProgress(TaskUserProgress progress) {

        // 如果用户是领取前三步的奖励，这里只要让他完成的步数加1就行了
        if (Objects.equals(progress.getStep(), TaskCenter.STEP_ONE)) {
            boolean insert = taskUserProgressMapper.insertSelective(progress) > 0;
            RedisUtil.delete(ActivityConstants.redisType.NEW_USER + progress.getUid());
            return insert;
        }

        if (progress.getStep() <= TaskCenter.STEP_THREE) {
            boolean update = taskUserProgressMapper.updateStepByUid(progress.getUid()) > 0;
            RedisUtil.delete(ActivityConstants.redisType.NEW_USER + progress.getUid());
            return update;
        }

        // 下面就是用户签到领取奖励的逻辑了
        TaskUserProgress taskUserProgress = taskUserProgressMapper.selectByUid(progress.getUid());
        int affectCount;
        if (Objects.isNull(taskUserProgress)) {
            progress.setFinishCount(1);
            progress.setLeastFinishTime(new Date());
            affectCount = taskUserProgressMapper.insertSelective(progress);
            RedisUtil.delete(ActivityConstants.redisType.NEW_USER + progress.getUid());
        } else {
            Date leastFinishTime = taskUserProgress.getLeastFinishTime();
            if (Objects.equals(taskUserProgress.getStep(), TaskCenter.STEP_THREE)) {
                taskUserProgress.setStep(taskUserProgress.getStep() + TaskCenter.STEP_ONE);
                taskUserProgress.setFinishCount(1);
                taskUserProgress.setLeastFinishTime(new Date());
                affectCount = taskUserProgressMapper.updateByPrimaryKeySelective(taskUserProgress);
                RedisUtil.delete(ActivityConstants.redisType.NEW_USER + progress.getUid());
            } else {
                if (isConsecutiveDays(leastFinishTime)) {
                    log.info("上一次领取奖励的UTC-0时间是[{}], 现在的UTC-0的时间是[{}]。两个时间是连续的两天，需要连续天数 + 1",
                            LocalDateTimeUtil.of(DateUtil.convertTimeZone(taskUserProgress.getLeastFinishTime(), ZoneId.of("UTC"))),
                            LocalDateTimeUtil.of(DateUtil.convertTimeZone(new Date(), ZoneId.of("UTC"))));
                    affectCount = taskUserProgressMapper.updateByUid(progress.getUid(), new Date());
                    RedisUtil.delete(ActivityConstants.redisType.NEW_USER + progress.getUid());
                } else {
                    affectCount = taskUserProgressMapper.updateFinishCount(progress.getUid(), new Date());
                    RedisUtil.delete(ActivityConstants.redisType.NEW_USER + progress.getUid());
                }
            }
        }
        return affectCount > 0;
    }

    /**
     * 是否是UTC相邻的两天
     *
     * @param day 上次领取奖励的时间
     * @return 是否是相邻的两天
     */
    public static Boolean isConsecutiveDays(Date day) {
        if (Objects.isNull(day)) return Boolean.FALSE;
        LocalDateTime start = LocalDateTimeUtil.beginOfDay(DateUtil.convertTimeZone(day, ZoneId.of("UTC")).toLocalDateTime().plusDays(1L));
        LocalDateTime end = LocalDateTimeUtil.endOfDay(DateUtil.convertTimeZone(day, ZoneId.of("UTC")).toLocalDateTime().plusDays(1L));
        LocalDateTime now = LocalDateTimeUtil.of(DateUtil.convertTimeZone(new Date(), ZoneId.of("UTC")));
        return now.isAfter(start) && now.isBefore(end);
    }


    // 判断两个UTC时间是不是同一天
    public static Boolean isSameDay(Date first, Date second) {
        LocalDateTime one = LocalDateTimeUtil.of(DateUtil.convertTimeZone(first, ZoneId.of("UTC")));
        LocalDateTime two = LocalDateTimeUtil.of(DateUtil.convertTimeZone(second, ZoneId.of("UTC")));
        return LocalDateTimeUtil.isSameDay(one, two);
    }

    // UTC当前时间是否在目标时间的第二天甚至以后
    public static Boolean isAfterDay(Date leastFinishTime) {
        LocalDateTime leastTime = LocalDateTimeUtil.endOfDay(DateUtil.convertTimeZone(leastFinishTime, ZoneId.of("UTC")).toLocalDateTime());
        LocalDateTime now = LocalDateTimeUtil.of(DateUtil.convertTimeZone(new Date(), ZoneId.of("UTC")));
        return now.isAfter(leastTime);
    }

    /**
     * 判断用户是否为老用户 逻辑：项目上线的版本之前注册的用户是老用户，之后注册的用户是新用户
     *
     * @param uid 用户ID
     * @return 是否是老用户
     */
    public Boolean isOldUser(Long uid) {
        ReturnResult<UserResponse> userResult = userApi.info(uid);

        if (userResult.isSuccess() && Objects.nonNull(userResult.getData())) {
            TaskVersionConfig taskVersionConfig;
            String repeatKey = ActivityConstants.redisType.TASK_VERSION_CONFIG;
            Object taskVersionConfigString = RedisUtil.get(repeatKey);

            if (null != taskVersionConfigString) {
                taskVersionConfig = JSON.parseObject(taskVersionConfigString.toString(), TaskVersionConfig.class);
            } else {
                taskVersionConfig = taskVersionConfigMapper.selectFirstVersion();
                String taskString = JSON.toJSONString(taskVersionConfig);
                RedisUtil.set(repeatKey, taskString);
            }

            return userResult.getData().getCreateTime().before(taskVersionConfig.getOnlineTime());
        }
        return Boolean.FALSE;
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public boolean updateTaskIdAndCount(Long id, Long taskId, Integer rechargeCount, Integer transactionCount) {
        return taskVersionInfoMapper.updateTaskIdAndCount(id, taskId, rechargeCount, transactionCount) > 0;
    }

    private static void setAttribute(Integer step, TaskAwardLog taskAwardLog) {
        switch (step) {
            case 1:
                taskAwardLog.setRemark("注册自动赠送");
                taskAwardLog.setTaskType(TaskCenter.REGISTER_TASK);
                break;
            case 2:
                taskAwardLog.setRemark("入金自动赠送");
                taskAwardLog.setTaskType(TaskCenter.INC_TASK);
                break;
            case 3:
                taskAwardLog.setRemark("交易自动赠送");
                taskAwardLog.setTaskType(TaskCenter.TRADING_TASK);
                break;
            default:
                taskAwardLog.setRemark("签到奖励");
                taskAwardLog.setTaskType(TaskCenter.SIGN_TASK);
        }
    }

    /**
     * 用户推特账号和小飞机账号信息录入
     *
     * @param taskData 推特账号和小飞机账号
     * @return
     */
    public Boolean insertOrUpdateTaskData(TaskData taskData) {
        TaskData result = taskDataMapper.selectOneByUserId(taskData.getUserId());
        int affectCount;
        if (Objects.isNull(result)) {
            affectCount = taskDataMapper.insertSelective(taskData);
        } else {
            if (StringUtils.isBlank(taskData.getTelegram())) {
                result.setTwitter(taskData.getTwitter());
                result.setTwitterTime(new Date());
            } else {
                result.setTelegram(taskData.getTelegram());
                result.setTelegramTime(new Date());
            }
            affectCount = taskDataMapper.updateByPrimaryKeySelective(result);
        }
        return affectCount > 0;
    }


    /**
     * 用户是否follow真实性校验
     *
     * @return 是否真实的关注
     */
    private String verifyFollow(Long userId, String account) {

        List<TaskData> taskDataList = taskDataMapper.selectByTwitter(account);
        if (!taskDataList.isEmpty() && !Objects.equals(taskDataList.get(0).getUserId(), userId)) {
            return InternationalCode.TWITTER_EXIST;
        }

        // 老数据查询
        TaskData taskData = taskDataMapper.selectOneByUserId(userId);

        // 如果存在老数据
        if (Objects.nonNull(taskData) && StrUtil.isNotBlank(taskData.getTwitter())) {
            if (invokeRapidApi(taskData.getTwitter())) {
                // 校验通过
                return InternationalCode.OPERATION_SUCCESS;
            } else if (invokeRapidApi(account)) {
                // 校验不通过校验新的账号，更新掉
                taskData.setTwitter(account);
                taskDataMapper.updateByPrimaryKeySelective(taskData);
                return InternationalCode.OPERATION_SUCCESS;
            }
        } else {
            // 不存在老数据的话，验证新数据，验证通过直接插入
            if (invokeRapidApi(account)) {
                TaskData taskDataNew = new TaskData();
                taskDataNew.setTwitter(account);
                taskDataNew.setUserId(userId);
                taskDataMapper.insertSelective(taskDataNew);
                return InternationalCode.OPERATION_SUCCESS;
            }
        }
        return InternationalCode.TWITTER_ID_UNFOLLOW;
    }


    /**
     * 调用rapid api
     *
     * @param twitterName twitter名称
     * @return 是否真实关注
     */
    @RetryOnFailure(maximum = 2) // 自定义注解+AOP实现RPC远程调用报错重试
    private boolean invokeRapidApi(String twitterName) {

        // GET 请求
        HttpResponse response = null;
        try {
            response = HttpRequest.get(String.format(RAPID_API, twitterName))
                    .header("X-RapidAPI-Key", apiKey)
                    .header("X-RapidAPI-Host", apiHost)
//                    .setHttpProxy("127.0.0.1", 7890)
                    .timeout(8 * 1000)
                    .execute();
        } catch (Exception e) {
            throw new BusinessException("Check failed, please try again");
        }


        // 抛出来异常，aop拦截到，发起重试
        if (!response.isOk()) {
            log.info("调用rapid_api报错，关注人的twitter名称：{}", twitterName);
            throw new RuntimeException("调用rapid_api报错");
        }

        // 将得到的结果使用Optional+stream流筛选出来结果
        return Optional.of(response)
                .map(HttpResponse::body)
                .map(JSON::parseObject)
                .map(json -> json.get("is_follow"))
                .map(Object::toString)
                .map(Boolean::parseBoolean)
                .orElse(Boolean.FALSE);
    }
}
